package com.csust.automaticteach.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.csust.automaticteach.constant.UserAuthConstant;
import com.csust.automaticteach.exception.ErrorCode;
import com.csust.automaticteach.exception.ThrowUtils;
import com.csust.automaticteach.model.dto.chathistory.ChatHistoryQueryRequest;
import com.csust.automaticteach.model.entity.ChatHistory;
import com.csust.automaticteach.model.entity.LearnChat;
import com.csust.automaticteach.model.entity.User;
import com.csust.automaticteach.model.enums.BizTypeEnum;
import com.csust.automaticteach.model.enums.ChatHistoryMessageTypeEnum;
import com.csust.automaticteach.service.ChatHistoryService;
import com.csust.automaticteach.mapper.ChatHistoryMapper;
import com.csust.automaticteach.service.LearnChatService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;

import static com.csust.automaticteach.constant.OrderConstant.ASC;

/**
* @author 钰玟
* @ description 针对表【t_chat_history(对话历史)】的数据库操作Service实现
* @ createDate 2025-09-27 13:36:20
*/
@Service
@Slf4j
public class ChatHistoryServiceImpl extends ServiceImpl<ChatHistoryMapper, ChatHistory>
    implements ChatHistoryService{

    private final LearnChatService learnChatService;

    public ChatHistoryServiceImpl(LearnChatService learnChatService) {
        this.learnChatService = learnChatService;
    }

    /**
     * 添加对话消息
     * @param bizId 业务ID
     * @param bizType 业务类型
     * @param message 消息
     * @param messageType 消息类型
     * @param userId 用户ID
     * @return 添加结果
     */
    @Override
    public boolean addChatMessage(Long bizId,Integer bizType, String message, String messageType, Long userId) {
        ThrowUtils.throwIf(ObjUtil.isNull(bizType), ErrorCode.PARAMS_ERROR, "业务类型不能为空");
        ThrowUtils.throwIf(bizId == null || bizId <= 0, ErrorCode.PARAMS_ERROR, "业务ID不能为空");
        ThrowUtils.throwIf(StrUtil.isBlank(message), ErrorCode.PARAMS_ERROR, "消息内容不能为空");
        ThrowUtils.throwIf(StrUtil.isBlank(messageType), ErrorCode.PARAMS_ERROR, "消息类型不能为空");
        ThrowUtils.throwIf(userId == null || userId <= 0, ErrorCode.PARAMS_ERROR, "用户ID不能为空");
        //验证业务类型是否有效
        BizTypeEnum bizTypeEnum = BizTypeEnum.getEnumByValue(bizType);
        ThrowUtils.throwIf(bizTypeEnum == null, ErrorCode.PARAMS_ERROR, "不支持的业务类型: " + bizTypeEnum);
        // 验证消息类型是否有效
        ChatHistoryMessageTypeEnum messageTypeEnum = ChatHistoryMessageTypeEnum.getEnumByValue(messageType);
        ThrowUtils.throwIf(messageTypeEnum == null, ErrorCode.PARAMS_ERROR, "不支持的消息类型: " + messageType);
        ChatHistory chatHistory = ChatHistory.builder()
                .bizId(bizId)
                .bizType(bizType)
                .message(message)
                .messageType(messageType)
                .userId(userId)
                .build();
        return this.save(chatHistory);
    }

    /**
     * 根据业务ID和业务类型删除对话消息
     * @param bizId 业务ID
     * @param bizType 业务类型
     * @return 删除结果
     */
    @Override
    public boolean deleteChatMessage(Long bizId, Integer bizType){
        //校验参数
        ThrowUtils.throwIf(ObjUtil.isNull(bizType), ErrorCode.PARAMS_ERROR, "业务类型不能为空");
        ThrowUtils.throwIf(bizId == null || bizId <= 0, ErrorCode.PARAMS_ERROR, "业务ID不能为空");
        //验证业务类型是否有效
        BizTypeEnum bizTypeEnum = BizTypeEnum.getEnumByValue(bizType);
        ThrowUtils.throwIf(bizTypeEnum == null, ErrorCode.PARAMS_ERROR, "不支持的业务类型: " + bizTypeEnum);
        //构建删除条件
        HashMap<String, Object> removeParam = new HashMap<>();
        removeParam.put("bizId", bizId);
        removeParam.put("bizType", bizType);
        // 删除
        return this.removeByMap(removeParam);
    }
    /**
     * 获取查询包装类
     *
     * @param chatHistoryQueryRequest  查询参数
     * @return   查询包装类
     */
    @Override
    public QueryWrapper<ChatHistory> getQueryWrapper(ChatHistoryQueryRequest chatHistoryQueryRequest) {
        QueryWrapper<ChatHistory> queryWrapper = new QueryWrapper<>();
        if (chatHistoryQueryRequest == null) {
            return queryWrapper;
        }
        Long id = chatHistoryQueryRequest.getId();
        String message = chatHistoryQueryRequest.getMessage();
        String messageType = chatHistoryQueryRequest.getMessageType();
        Long bizId = chatHistoryQueryRequest.getBizId();
        Integer bizType = chatHistoryQueryRequest.getBizType();
        Long userId = chatHistoryQueryRequest.getUserId();
        LocalDateTime lastCreateTime = chatHistoryQueryRequest.getLastCreateTime();
        String sortField = chatHistoryQueryRequest.getSortField();
        String sortOrder = chatHistoryQueryRequest.getSortOrder();
        // 拼接查询条件
        queryWrapper.eq(ObjUtil.isNotNull(id),"id", id)
                .like(StrUtil.isNotBlank(message),"message", message)
                .eq(StrUtil.isNotBlank(messageType),"messageType", messageType)
                .eq(ObjUtil.isNotNull(bizId),"bizId", bizId)
                .eq(ObjUtil.isNotNull(bizType),"bizType", bizType)
                .eq(ObjUtil.isNotNull(userId),"userId", userId);
        // 游标查询逻辑 - 只使用 createTime 作为游标
        if (lastCreateTime != null) {
            queryWrapper.lt("createTime", lastCreateTime);
        }
        // 排序
        if (StrUtil.isNotBlank(sortField)) {
            queryWrapper.orderBy(StrUtil.isNotBlank(sortField), ASC.equals(sortOrder),sortField);
        } else {
            // 默认按创建时间降序排列
            queryWrapper.orderBy(true,false,"createTime");
        }
        return queryWrapper;
    }

    /**
     *  获取用户对话历史
     * @param bizId 业务ID
     * @param bizType 业务类型
     * @param pageSize 页面大小
     * @param lastCreateTime 最后创建时间
     * @param loginUser 登录用户
     * @return 用户对话历史
     */
    @Override
    public Page<ChatHistory> listAppChatHistoryByPage(Long bizId, Integer bizType, int pageSize,
                                                      LocalDateTime lastCreateTime,
                                                      User loginUser) {
        ThrowUtils.throwIf(bizId == null || bizId <= 0, ErrorCode.PARAMS_ERROR, "业务ID不能为空");
        ThrowUtils.throwIf(bizType == null || bizType < 0, ErrorCode.PARAMS_ERROR, "业务类型不能为空");
        ThrowUtils.throwIf(pageSize <= 0 || pageSize > 50, ErrorCode.PARAMS_ERROR, "页面大小必须在1-50之间");
        ThrowUtils.throwIf(loginUser == null, ErrorCode.NOT_LOGIN_ERROR);
        //验证业务类型是否有效
        BizTypeEnum bizTypeEnum = BizTypeEnum.getEnumByValue(bizType);
        ThrowUtils.throwIf(bizTypeEnum == null, ErrorCode.PARAMS_ERROR, "不支持的业务类型: " + bizTypeEnum);
        // 验证权限：只有应用创建者和管理员可以查看
        //todo 写死了learnChat 业务类型
        LearnChat learnChat = learnChatService.getById(bizId);
        ThrowUtils.throwIf(learnChat == null, ErrorCode.NOT_FOUND_ERROR, "对话不存在");
        boolean isAdmin = UserAuthConstant.ADMIN_ROLE.equals(loginUser.getUserRole());
        boolean isCreator = learnChat.getUserId().equals(loginUser.getId());
        ThrowUtils.throwIf(!isAdmin && !isCreator, ErrorCode.NO_AUTH_ERROR, "无权查看该业务的对话历史");
        // 构建查询条件
        ChatHistoryQueryRequest queryRequest = new ChatHistoryQueryRequest();
        queryRequest.setBizId(bizId);
        queryRequest.setBizType(bizType);
        queryRequest.setLastCreateTime(lastCreateTime);
        QueryWrapper<ChatHistory> queryWrapper = this.getQueryWrapper(queryRequest);
        // 查询数据
        return this.page(Page.of(1, pageSize), queryWrapper);
    }

    /**
     *  加载对话历史到内存
     * @param bizId 业务ID
     * @param bizType 业务类型
     * @param chatMemory 缓存
     * @param maxCount 最大加载数量
     * @return 加载数量
     */
    @Override
    public int loadChatHistoryToMemory(Long bizId, Integer bizType, ChatMemory chatMemory, int maxCount) {
        log.info("开始加载对话历史到 redis 内存...,业务id：{}，业务类型:{}", bizId, BizTypeEnum.getEnumByValue(bizType));
        List<Message> messages = chatMemory.get(String.valueOf(bizId));
        if (CollUtil.isEmpty(messages)) {
            try {
                // 直接构造查询条件，起始点为 1 而不是 0，用于排除最新的用户消息
                QueryWrapper<ChatHistory> queryWrapper = new QueryWrapper<>();
                queryWrapper
//                        .select("message", "messageType")
                        .eq(ObjUtil.isNotNull(bizId), "bizId", bizId)
                        .eq(ObjUtil.isNotNull(bizType), "bizType", bizType)
                        .orderBy(true, false, "CreateTime")
                        .last(maxCount > 0, " LIMIT 1," + maxCount);
                List<ChatHistory> historyList = this.list(queryWrapper);
                if (CollUtil.isEmpty(historyList)) {
                    return 0;
                }
                // 反转列表，确保按时间正序（老的在前，新的在后）
                historyList = historyList.reversed();
                // 按时间顺序添加到记忆中
                int loadedCount = 0;
                // 先清理历史缓存，防止重复加载
                chatMemory.clear(String.valueOf(bizId));
                for (ChatHistory history : historyList) {
                    if (ChatHistoryMessageTypeEnum.USER.getValue().equals(history.getMessageType())) {
                        chatMemory.add(String.valueOf(bizId), UserMessage.builder().text(history.getMessage()).build());
                        loadedCount++;
                    } else if (ChatHistoryMessageTypeEnum.AI.getValue().equals(history.getMessageType())) {
                        chatMemory.add(String.valueOf(bizId), new AssistantMessage(history.getMessage()));
                        loadedCount++;
                    }
                }
                log.info("成功为 bizId: {} 加载了 {} 条历史对话", bizId, loadedCount);
                return loadedCount;
            } catch (Exception e) {
                log.error("加载历史对话失败，bizId: {}, error: {}", bizId, e.getMessage(), e);
                // 加载失败不影响系统运行，只是没有历史上下文
                return 0;
            }
        }
        return 0;
    }



}




